package com.openbravo.pos.sales;

import java.awt.Component;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import javax.print.PrintService;
import javax.swing.JComponent;
import javax.swing.JPanel;

import cn.ekuma.epos.bean.util.RoleSwingUtil;
import com.openbravo.pos.base.*;
import com.openbravo.pos.forms.JRootApp;
import e.odbo.data.dao.ListKeyed;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRMapArrayDataSource;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.xml.JRXmlLoader;

import cn.ekuma.data.ui.swing.JEditorWarpDialog;
import cn.ekuma.epos.bean.util.PaymentInfoHelper;
import cn.ekuma.epos.bean.util.sale.TicketHelper;
import cn.ekuma.epos.bean.util.sale.TicketLineHelper;
import cn.ekuma.epos.bean.util.sale.TicketLineWarp;
import cn.ekuma.epos.bean.util.sale.TicketWarp;
import cn.ekuma.epos.businesslogic.RoleUtil;
import cn.ekuma.epos.businesslogic.TicketUtil;
import cn.ekuma.epos.core.util.ProductSwingUtil;
import cn.ekuma.epos.datalogic.I_DataLogicCustomers;
import cn.ekuma.epos.datalogic.I_DataLogicReceipts;
import cn.ekuma.epos.datalogic.I_DataLogicSales;
import cn.ekuma.epos.datalogic.I_DataLogicSystem;
import cn.ekuma.epos.datalogic.define.DataLogicSystemHelper;
import cn.ekuma.epos.servings.JServingsEditorDialog;
import cn.ekuma.rabbit.spi.I_ModelPart;
import cn.ekuma.security.I_SecurityManager;

import com.openbravo.bean.AppUser;
import com.openbravo.bean.BusinessPartner;
import com.openbravo.bean.PaymentInfo;
import com.openbravo.bean.PaymentInfoCash;
import com.openbravo.bean.Product;
import com.openbravo.bean.ProductScore;
import com.openbravo.bean.Serving;
import com.openbravo.bean.Tax;
import com.openbravo.bean.TaxCategory;
import com.openbravo.bean.infobean.CustomerInfo;
import com.openbravo.bean.sales.Ticket;
import com.openbravo.bean.sales.TicketLine;
import com.openbravo.data.basic.BasicException;
import com.openbravo.data.gui.ComboBoxValModel;
import com.openbravo.data.gui.JMessageDialog;
import com.openbravo.data.gui.MessageInf;
import com.openbravo.data.user.DirtyManager;

import com.openbravo.pos.customers.CustomersEditor;
import com.openbravo.pos.forms.JPanelView;
import com.openbravo.pos.mode.POS_UI_Swing_Model;
import com.openbravo.pos.panels.JCustomerFinder;
import com.openbravo.pos.panels.JPanelButtons;
import com.openbravo.pos.panels.JProductAttEdit;
import com.openbravo.pos.panels.JProductDetail;
import com.openbravo.pos.panels.JProductFinder;
import com.openbravo.pos.payment.JPaymentSelect;
import com.openbravo.pos.printer.AbstractTicketPrintManager;
import com.openbravo.pos.printer.TicketParser;
import com.openbravo.pos.printer.TicketPrinterException;
import com.openbravo.pos.sales.event.TicketEvent;
import com.openbravo.pos.sales.event.TicketLineEvent;
import com.openbravo.pos.scale.ScaleException;
import com.openbravo.pos.scripting.ScriptEngine;
import com.openbravo.pos.scripting.ScriptException;
import com.openbravo.pos.scripting.ScriptFactory;
import com.openbravo.pos.util.JRPrinterAWT300;
import com.openbravo.pos.util.ReportUtils;

public abstract class AbstractJPanelTicket extends JPanel implements JPanelView, BeanFactoryApp, TicketsEditor, I_ScriptCommand, I_ModelPart<POS_UI_Swing_Model> {


    protected static final int NUMBERZERO = 0;
    protected static final int NUMBERVALID = 1;
    protected static final int NUMBER_INPUTZERO = 0;
    private static final int NUMBER_INPUTZERODEC = 1;
    private static final int NUMBER_INPUTINT = 2;
    private static final int NUMBER_INPUTDEC = 3;
    private static final int NUMBER_PORZERO = 4;
    private static final int NUMBER_PORZERODEC = 5;
    private static final int NUMBER_PORINT = 6;
    private static final int NUMBER_PORDEC = 7;
    protected JTicketLines m_ticketlines;
    protected TicketParser m_TTP;
    protected Ticket m_oTicket;
    protected Object m_oTicketExt;
    protected int m_iNumberStatus;
    protected int m_iNumberStatusInput;
    protected int m_iNumberStatusPor;
    protected StringBuffer m_sBarcode;
    protected JTicketsBag m_ticketsbag;
    protected ListKeyed taxcollection;
    protected ComboBoxValModel taxcategoriesmodel;
    protected TaxesLogic taxeslogic;
    protected JPanelButtons m_jbtnconfig;
    protected JRootApp m_App;
    protected I_DataLogicSystem dlSystem;
    protected I_DataLogicSales dlSales;
    protected I_DataLogicCustomers dlCustomers;
    protected I_DataLogicReceipts dlReceipts;
    protected JPaymentSelect paymentdialogreceipt;
    protected JPaymentSelect paymentdialogrefund;
    private JEditorWarpDialog productCreateDialog;
    private JEditorWarpDialog customerCreateDialog;
    protected String cashChanged;
    protected AbstractTicketPrintManager printManager;
    protected boolean quickSellAble;
    protected String cashPaid;
    protected String priceGroup;
    boolean isEditAble = false;
    protected boolean isCheckProductLocation;
    protected I_SecurityManager security;

    public void init(I_AppView app) throws BeanFactoryException {
        m_App = (JRootApp) app;

        m_TTP = new TicketParser(m_App.getDeviceTicket(), dlSystem);
    }


    public boolean deactivate() {
        return m_ticketsbag.deactivate();
    }

    @Override
    public Object getBean() {
        return this;
    }

    @Override
    public JComponent getComponent() {
        return this;
    }

    protected abstract JTicketsBag getJTicketsBag();

    protected abstract Component getSouthComponent();

    protected abstract void resetSouthComponent();

    protected abstract void stateToZero();

    protected abstract void printPartialTotals();

    protected abstract void refreshTicketLineSelectedState();

    protected abstract void refreshTicket();


    public void setActiveTicket(Ticket oTicket, Object oTicketExt, boolean isEditAble) {

        m_oTicket = oTicket;
        m_oTicketExt = oTicketExt;
        this.isEditAble = isEditAble;
        if (m_oTicket != null && isEditAble) {
            // Asign preeliminary properties to the receipt
            m_oTicket.setUser(m_App.getUserInfo());
            m_oTicket.setActiveCash(m_App.getUserCashIndex());
            m_oTicket.setDate(new Date()); // Set the edition date.
        }

        executeEvent(m_oTicket, m_oTicketExt, "ticket.show");

        refreshTicket();
    }


    @Override
    public Ticket getActiveTicket() {
        return m_oTicket;
    }


    private void paintTicketLine(int index, TicketLine oLine) {

        if (executeEventAndRefresh("ticket.setline", new ScriptArg("index",
                index), new ScriptArg("line", oLine)) == null) {

            TicketLine oldLine = m_oTicket.getLine(index);

            m_oTicket.setLine(index, oLine);
            m_ticketlines.setTicketLine(index, oLine);
            m_ticketlines.setSelectedIndex(index);
            try {
                for (I_TicketLinePrintListener l : listenerList
                        .getListeners(I_TicketLinePrintListener.class))
                    l.fireTicketLineChanged(new TicketLineEvent(oldLine, oLine));
            } catch (ScriptException e) {
                MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                        AppLocal.getIntString("message.cannotprintticket"), e);
                msg.show(AbstractJPanelTicket.this);
            } catch (TicketPrinterException e) {
                MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                        AppLocal.getIntString("message.cannotprintticket"), e);
                msg.show(AbstractJPanelTicket.this);
            }
            visorTicketLine(oLine); // Y al visor tambien...
            printPartialTotals();
            stateToZero();

            // event receipt
            executeEventAndRefresh("ticket.change");
        }
    }

    private void addTicketLine(Product oProduct, double dMul, double dPrice) {

        Tax tax = taxeslogic.getTaxInfo(oProduct.getTaxCategoryID(),
                m_oTicket.getCustomer());

        addTicketLine(new TicketLine(oProduct, dMul, dPrice, tax,
                (java.util.HashMap) (oProduct.getProperties().clone()),
                m_oTicket.getM_dPriceRate()));
    }

    protected void addTicketLine(TicketLine oLine) {

        if (executeEventAndRefresh("ticket.addline", new ScriptArg("line",
                oLine)) == null) {

            if (oLine.isProductCom()) {
                // Comentario entonces donde se pueda
                int i = m_ticketlines.getSelectedIndex();

                // me salto el primer producto normal...
                if (i >= 0 && !m_oTicket.getLine(i).isProductCom()) {
                    i++;
                }

                // me salto todos los productos auxiliares...
                while (i >= 0 && i < m_oTicket.getLinesCount()
                        && m_oTicket.getLine(i).isProductCom()) {
                    i++;
                }

                if (i >= 0) {
                    TicketLine newAddLine;
                    try {
                        newAddLine = TicketUtil.insertLine(dlSales, m_oTicket,
                                i, oLine, m_App.getDefineLocation());
                        TicketUtil.checkTicketLineProductScore(dlSales, m_oTicket, oLine, ProductScore.TYPE_Store, m_App.getDefineLocation());
                        m_ticketlines.insertTicketLine(i, oLine); // Pintamos la
                        // linea en la
                        // vista...
                        if (newAddLine != null) {
                            m_ticketlines.insertTicketLine(i + 1, newAddLine);
                        }
                    } catch (BasicException e) {
                        new MessageInf(e).show(AbstractJPanelTicket.this);
                    }

                } else {
                    Toolkit.getDefaultToolkit().beep();
                }
            } else {
                // Producto normal, entonces al finalnewline.getMultiply()
                TicketLine newAddLine = null;
                try {
                    newAddLine = TicketUtil.addLine(dlSales, m_oTicket,
                            oLine, m_App.getDefineLocation());
                    TicketUtil.checkTicketLineProductScore(dlSales, m_oTicket, oLine, ProductScore.TYPE_Store, m_App.getDefineLocation());
                    m_ticketlines.addTicketLine(oLine); // Pintamos la linea en la
                    // vista...

                } catch (BasicException e1) {
                    new MessageInf(e1).show(AbstractJPanelTicket.this);
                    return;
                }
                try {
                    for (I_TicketLinePrintListener l : listenerList
                            .getListeners(I_TicketLinePrintListener.class))
                        l.fireTicketLineAdded(new TicketLineEvent(oLine));
                } catch (ScriptException e) {
                    MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                            AppLocal.getIntString("message.cannotprintticket"),
                            e);
                    msg.show(AbstractJPanelTicket.this);
                } catch (TicketPrinterException e) {
                    MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                            AppLocal.getIntString("message.cannotprintticket"),
                            e);
                    msg.show(AbstractJPanelTicket.this);
                }
                if (newAddLine != null) {
                    Tax tax = taxeslogic.getTaxInfo(
                            newAddLine.getProductTaxCategoryID(),
                            m_oTicket.getCustomer());
                    newAddLine.setTaxInfo(tax);
                    m_ticketlines.addTicketLine(newAddLine);
                    try {
                        for (I_TicketLinePrintListener l : listenerList
                                .getListeners(I_TicketLinePrintListener.class))
                            l.fireTicketLineAdded(new TicketLineEvent(
                                    newAddLine));
                    } catch (ScriptException e) {
                        MessageInf msg = new MessageInf(
                                MessageInf.SGN_WARNING,
                                AppLocal.getIntString("message.cannotprintticket"),
                                e);
                        msg.show(AbstractJPanelTicket.this);
                    } catch (TicketPrinterException e) {
                        MessageInf msg = new MessageInf(
                                MessageInf.SGN_WARNING,
                                AppLocal.getIntString("message.cannotprintticket"),
                                e);
                        msg.show(AbstractJPanelTicket.this);
                    }
                }
            }

            visorTicketLine(oLine);
            printPartialTotals();
            stateToZero();

            // event receipt
            executeEventAndRefresh("ticket.change");
        }
    }

    private void removeTicketLine(int i) {
        if (!RoleSwingUtil.hasPermission(AbstractJPanelTicket.this, (AppUser) m_App
                        .getAppUserView().getUser(), dlSystem,
                RoleUtil.Permission_EDIT_TICKET_LINE))
            return;
        if (executeEventAndRefresh("ticket.removeline", new ScriptArg("index",
                i)) == null) {

            if (m_oTicket.getLine(i).isProductCom()) {
                // Es un producto auxiliar, lo borro y santas pascuas.
                m_oTicket.removeLine(i);
                m_ticketlines.removeTicketLine(i);
            } else {
                TicketLine removeLine = m_oTicket.getLine(i);

                // Es un producto normal, lo borro.
                m_oTicket.removeLine(i);
                m_ticketlines.removeTicketLine(i);
                try {
                    for (I_TicketLinePrintListener l : listenerList
                            .getListeners(I_TicketLinePrintListener.class))
                        l.fireTicketLineDeleted(new TicketLineEvent(removeLine));
                } catch (ScriptException e) {
                    MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                            AppLocal.getIntString("message.cannotprintticket"),
                            e);
                    msg.show(AbstractJPanelTicket.this);
                } catch (TicketPrinterException e) {
                    MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                            AppLocal.getIntString("message.cannotprintticket"),
                            e);
                    msg.show(AbstractJPanelTicket.this);
                }
                // Y todos lo auxiliaries que hubiera debajo.
                while (i < m_oTicket.getLinesCount()
                        && m_oTicket.getLine(i).isProductCom()) {
                    m_oTicket.removeLine(i);
                    m_ticketlines.removeTicketLine(i);
                }
            }

            visorTicketLine(null); // borro el visor
            printPartialTotals(); // pinto los totales parciales...
            stateToZero(); // Pongo a cero

            // event receipt
            executeEventAndRefresh("ticket.change");
        }
    }

    @Override
    public ListKeyed getTaxCollection() {
        return taxcollection;
    }

    @Override
    public TaxesLogic getTaxLogic() {
        return taxeslogic;
    }

    @Override
    public Object getTicketExt() {
        return m_oTicketExt;
    }


    private Product getInputProduct() {
        Product oProduct = new Product(); // Es un ticket
        oProduct.setReference(null);
        oProduct.setCode(null);
        oProduct.setName("");
        oProduct.setTaxCategoryID(((TaxCategory) taxcategoriesmodel
                .getSelectedItem()).getID());

        oProduct.setPriceSell(includeTaxes(oProduct.getTaxCategoryID(),
                getInputValue()));

        return oProduct;
    }

    private double includeTaxes(String tcid, double dValue) {
        if (m_jaddtax.isSelected()) {
            Tax tax = taxeslogic.getTaxInfo(tcid, m_oTicket.getCustomer());
            double dTaxRate = tax == null ? 0.0 : tax.getRate();
            return dValue / (1.0 + dTaxRate);
        } else {
            return dValue;
        }
    }

    protected double getInputValue() {
        try {
            return Double.parseDouble(m_jPrice.getText());
        } catch (NumberFormatException e) {
            return 0.0;
        }
    }

    private double getPorValue() {
        try {
            return Double.parseDouble(m_jPor.getText().substring(1));
        } catch (NumberFormatException e) {
            return 1.0;
        } catch (StringIndexOutOfBoundsException e) {
            return 1.0;
        }
    }

    private void incProductByCode(String sCode) {
        if (sCode.isEmpty()) {
            stateToZero();
            return;
        }
        boolean isSeachModel = false;
        // precondicion: sCode != null
        sCode.toUpperCase();
        try {
            Product oProduct = null;
            if (quickSellAble && sCode.startsWith("~")) {
                isSeachModel = true;
                java.util.List<Product> prods = dlSales.listProductByMnemonic(sCode.substring(1));
                if (prods != null && prods.size() > 0)
                    if (prods.size() == 1)
                        oProduct = prods.get(0);
                    else
                        oProduct = getProductFinder().setProductList(prods);
            } else {
                oProduct = ProductSwingUtil.getProductInfo(this, dlSales, sCode.trim());
            }
            if (oProduct == null) {
                Toolkit.getDefaultToolkit().beep();
                stateToZero();
                new MessageInf(MessageInf.SGN_WARNING, AppLocal.getIntString("message.noproduct")).show(this);
            } else {
                // Se anade directamente una unidad con el precio y todo
                incProduct(oProduct);
            }
        } catch (BasicException eData) {
            stateToZero();
            new MessageInf(eData).show(this);
        }
    }

    private void incProductByCodePrice(String sCode, double dPriceSell) {

        // precondicion: sCode != null
        Product oProduct = ProductSwingUtil.getProductInfo(this, dlSales, sCode);
        if (oProduct == null) {
            Toolkit.getDefaultToolkit().beep();
            new MessageInf(MessageInf.SGN_WARNING,
                    AppLocal.getIntString("message.noproduct")).show(this);
            stateToZero();
        } else {
            // Se anade directamente una unidad con el precio y todo
            if (m_jaddtax.isSelected()) {
                // debemos quitarle los impuestos ya que el precio es con
                // iva incluido...
                Tax tax = taxeslogic.getTaxInfo(
                        oProduct.getTaxCategoryID(),
                        m_oTicket.getCustomer());
                addTicketLine(oProduct, 1.0,
                        dPriceSell / (1.0 + tax.getRate()));
            } else {
                addTicketLine(oProduct, 1.0, dPriceSell);
            }
        }
    }

    private void incProductByCalcMult(String sCode, double dPriceSell) {
        // precondicion: sCode != null
        Product oProduct = ProductSwingUtil.getProductInfo(this, dlSales, sCode);
        if (oProduct == null) {
            Toolkit.getDefaultToolkit().beep();
            new MessageInf(MessageInf.SGN_WARNING,
                    AppLocal.getIntString("message.noproduct")).show(this);
            stateToZero();
        } else {
            double mult = dPriceSell / oProduct.getPriceSell();
            incProduct(mult, oProduct);
        }
    }

    private void incProductByMult(String sCode, double mult) {
        // precondicion: sCode != null
        Product oProduct = ProductSwingUtil.getProductInfo(this, dlSales, sCode);
        if (oProduct == null) {
            Toolkit.getDefaultToolkit().beep();
            new MessageInf(MessageInf.SGN_WARNING,
                    AppLocal.getIntString("message.noproduct")).show(this);
            stateToZero();
        } else {
            incProduct(mult, oProduct);
        }
    }

    protected void incProduct(Product prod) {
        try {
            if (prod.getID() != null && !dlSales.isProductOutAble(m_App.getInventoryLocation(), prod.getID())) {
                Toolkit.getDefaultToolkit().beep();
                new MessageInf(MessageInf.SGN_WARNING,
                        AppLocal.getIntString("message.productNoOutAble"))
                        .show(this);
                stateToZero();
                return;
            }
            if (prod.getID() != null && isCheckProductLocation && !dlSales.isProductStoreEnough(m_App.getInventoryLocation(), prod.getID(), 1)) {
                new MessageInf(MessageInf.SGN_WARNING, AppLocal.getIntString("message.productNoStoreEnough")).show(this);
                return;
            }
        } catch (BasicException e1) {
            new MessageInf(MessageInf.SGN_WARNING, e1.getMessage()).show(this);
            return;
        }

        if (prod.isScale() && m_App.getDeviceScale().existsScale()) {
            try {
                Double value = m_App.getDeviceScale().readWeight();
                if (value != null) {
                    incProduct(value.doubleValue(), prod);
                }
            } catch (ScaleException e) {
                Toolkit.getDefaultToolkit().beep();
                new MessageInf(MessageInf.SGN_WARNING,
                        AppLocal.getIntString("message.noweight"), e)
                        .show(this);
                stateToZero();
            }
        } else {
            // No es un producto que se pese o no hay balanza
            incProduct(1.0, prod);
        }
    }

    protected void incProduct(double dPor, Product prod) {
        // precondicion: prod != null
        BusinessPartner customer = m_oTicket.getCustomer();
        double salePrice = prod.getPriceSell();
        if (customer != null && prod.getM_dCustomerPrice() > 0) {
            salePrice = prod.getM_dCustomerPrice();
        }
        if (priceGroup != null) {
            try {
                salePrice = TicketUtil.getProductPrice(dlSales, customer, prod, priceGroup);
            } catch (BasicException e) {
                Toolkit.getDefaultToolkit().beep();
                new MessageInf(e).show(this);
                return;
            }
        }
        addTicketLine(prod, dPor, salePrice);
    }

    protected void buttonTransition(Product prod) {
        // precondicion: prod != null

        if (m_iNumberStatusInput == NUMBERZERO
                && m_iNumberStatusPor == NUMBERZERO) {
            incProduct(prod);
        } else if (m_iNumberStatusInput == NUMBERVALID
                && m_iNumberStatusPor == NUMBERZERO) {
            incProduct(getInputValue(), prod);
        } else {
            Toolkit.getDefaultToolkit().beep();
        }
    }

    private void stateTransition(char cTrans) {

        if (!isEditAble) {
            stateToZero();
            if (cTrans == '+') {
                m_ticketsbag.showNextTicket();
            } else if (cTrans == '-') {
                m_ticketsbag.showPrevTicket();
            } else
                m_ticketsbag.selectValidTicket();
            return;
        }
        if (cTrans == '\n') {
            // Codigo de barras introducido
            if (m_sBarcode.length() > 0) {
                String sCode = m_sBarcode.toString();
                if (sCode.startsWith("c")) {
                    // barcode of a customers card
                    try {
                        BusinessPartner newcustomer = dlSales.findCustomerByCard(sCode);
                        if (newcustomer == null)
                            newcustomer = dlSales.findCustomerByStoreCard(sCode.substring(1));
                        if (newcustomer == null) {
                            Toolkit.getDefaultToolkit().beep();
                            new MessageInf(MessageInf.SGN_WARNING,
                                    AppLocal.getIntString("message.nocustomer"))
                                    .show(this);
                        } else {
                            TicketUtil.changeCustomer(dlSales, m_oTicket,
                                    newcustomer, priceGroup);
                            m_oTicket.setCustomer(newcustomer);
                            m_jTicketId.setText(TicketHelper.getName(m_oTicket,
                                    m_oTicketExt));
                        }
                    } catch (BasicException e) {
                        Toolkit.getDefaultToolkit().beep();
                        new MessageInf(MessageInf.SGN_WARNING,
                                AppLocal.getIntString("message.nocustomer"), e)
                                .show(this);
                    }
                    stateToZero();
                } else if (sCode.length() == 13 && sCode.startsWith("250")) {
                    // barcode of the other machine
                    Product oProduct = new Product(); // Es un ticket
                    oProduct.setReference(null); // para que no se grabe
                    oProduct.setCode(sCode);
                    oProduct.setName("Ticket " + sCode.substring(3, 7));
                    oProduct.setPriceSell(Double.parseDouble(sCode.substring(7,
                            12)) / 100);
                    oProduct.setTaxCategoryID(((TaxCategory) taxcategoriesmodel
                            .getSelectedItem()).getID());
                    // Se anade directamente una unidad con el precio y todo
                    addTicketLine(
                            oProduct,
                            1.0,
                            includeTaxes(oProduct.getTaxCategoryID(),
                                    oProduct.getPriceSell()));
                } else if (sCode.length() == 13 && sCode.startsWith("210")) {
                    // barcode of a weigth product
                    incProductByCodePrice(sCode.substring(3, 7),
                            Double.parseDouble(sCode.substring(7, 12)) / 100);
                } else if (sCode.length() == 13 && sCode.startsWith("220")) {
                    // barcode of a weigth product
                    incProductByMult(sCode.substring(3, 7),
                            Double.parseDouble(sCode.substring(7, 12)) / 1000);
                } else if (sCode.length() == 13 && sCode.startsWith("230")) {
                    // barcode of a weigth product
                    incProductByCalcMult(sCode.substring(3, 7),
                            Double.parseDouble(sCode.substring(7, 12)) / 100);
                } else {
                    incProductByCode(sCode);
                }
            } else {
                Toolkit.getDefaultToolkit().beep();
            }
        } else {
            // otro caracter
            // Esto es para el codigo de barras...
            m_sBarcode.append(cTrans);

            // Esto es para el los productos normales...
            if (cTrans == '\u007f') {
                stateToZero();

            } else if (quickSellAble && (cTrans == '~' || cTrans == '～') && (m_iNumberStatus == NUMBER_INPUTZERO)) {
                m_jPrice.setText("~");
                m_iNumberStatus = NUMBER_INPUTINT;
                m_iNumberStatusInput = NUMBERVALID;
            } else if (String.valueOf(cTrans).matches("[A-Z|a-z]") && m_iNumberStatus == NUMBER_INPUTZERO && cTrans != 'c') {
                quickSaleByKeyStoke(cTrans);
            }/**else if ((cTrans == '0')  && (m_iNumberStatus == NUMBER_INPUTZERO)) {
             m_jPrice.setText("0");
             }**/
            else if ((cTrans == '0' || cTrans == '1' || cTrans == '2' || cTrans == '3'
                    || cTrans == '4' || cTrans == '5' || cTrans == '6'
                    || cTrans == '7' || cTrans == '8' || cTrans == '9')
                    && (m_iNumberStatus == NUMBER_INPUTZERO)) {
                // Un numero entero
                m_jPrice.setText(Character.toString(cTrans));
                m_iNumberStatus = NUMBER_INPUTINT;
                m_iNumberStatusInput = NUMBERVALID;
            } else if ((cTrans == '0' || cTrans == '1' || cTrans == '2'
                    || cTrans == '3' || cTrans == '4' || cTrans == '5'
                    || cTrans == '6' || cTrans == '7' || cTrans == '8' || cTrans == '9')
                    && (m_iNumberStatus == NUMBER_INPUTINT)) {
                // Un numero entero
                m_jPrice.setText(m_jPrice.getText() + cTrans);

            } else if (quickSellAble && String.valueOf(cTrans).matches("[A-Z|a-z]") && (m_iNumberStatus == NUMBER_INPUTZERO || m_iNumberStatus == NUMBER_INPUTINT)) {
                m_jPrice.setText(m_jPrice.getText() + cTrans);
            } else if (cTrans == '.' && m_iNumberStatus == NUMBER_INPUTZERO) {
                m_jPrice.setText("0.");
                m_iNumberStatus = NUMBER_INPUTZERODEC;
            } else if (cTrans == '.' && m_iNumberStatus == NUMBER_INPUTINT) {
                m_jPrice.setText(m_jPrice.getText() + ".");
                m_iNumberStatus = NUMBER_INPUTDEC;

            } else if ((cTrans == '0')
                    && (m_iNumberStatus == NUMBER_INPUTZERODEC || m_iNumberStatus == NUMBER_INPUTDEC)) {
                // Un numero decimal
                m_jPrice.setText(m_jPrice.getText() + cTrans);
            } else if ((cTrans == '1' || cTrans == '2' || cTrans == '3'
                    || cTrans == '4' || cTrans == '5' || cTrans == '6'
                    || cTrans == '7' || cTrans == '8' || cTrans == '9')
                    && (m_iNumberStatus == NUMBER_INPUTZERODEC || m_iNumberStatus == NUMBER_INPUTDEC)) {
                // Un numero decimal
                m_jPrice.setText(m_jPrice.getText() + cTrans);
                m_iNumberStatus = NUMBER_INPUTDEC;
                m_iNumberStatusInput = NUMBERVALID;

            } else if (cTrans == '*'
                    && (m_iNumberStatus == NUMBER_INPUTINT || m_iNumberStatus == NUMBER_INPUTDEC)) {
                m_jPor.setText("x");
                m_iNumberStatus = NUMBER_PORZERO;
            } else if (cTrans == '*'
                    && (m_iNumberStatus == NUMBER_INPUTZERO || m_iNumberStatus == NUMBER_INPUTZERODEC)) {
                m_jPrice.setText("0");
                m_jPor.setText("x");
                m_iNumberStatus = NUMBER_PORZERO;

            } else if ((cTrans == '0') && (m_iNumberStatus == NUMBER_PORZERO)) {
                m_jPor.setText("x0");
            } else if ((cTrans == '1' || cTrans == '2' || cTrans == '3'
                    || cTrans == '4' || cTrans == '5' || cTrans == '6'
                    || cTrans == '7' || cTrans == '8' || cTrans == '9')
                    && (m_iNumberStatus == NUMBER_PORZERO)) {
                // Un numero entero
                m_jPor.setText("x" + Character.toString(cTrans));
                m_iNumberStatus = NUMBER_PORINT;
                m_iNumberStatusPor = NUMBERVALID;
            } else if ((cTrans == '0' || cTrans == '1' || cTrans == '2'
                    || cTrans == '3' || cTrans == '4' || cTrans == '5'
                    || cTrans == '6' || cTrans == '7' || cTrans == '8' || cTrans == '9')
                    && (m_iNumberStatus == NUMBER_PORINT)) {
                // Un numero entero
                m_jPor.setText(m_jPor.getText() + cTrans);

            } else if (cTrans == '.' && m_iNumberStatus == NUMBER_PORZERO) {
                m_jPor.setText("x0.");
                m_iNumberStatus = NUMBER_PORZERODEC;
            } else if (cTrans == '.' && m_iNumberStatus == NUMBER_PORINT) {
                m_jPor.setText(m_jPor.getText() + ".");
                m_iNumberStatus = NUMBER_PORDEC;

            } else if ((cTrans == '0')
                    && (m_iNumberStatus == NUMBER_PORZERODEC || m_iNumberStatus == NUMBER_PORDEC)) {
                // Un numero decimal
                m_jPor.setText(m_jPor.getText() + cTrans);
            } else if ((cTrans == '1' || cTrans == '2' || cTrans == '3'
                    || cTrans == '4' || cTrans == '5' || cTrans == '6'
                    || cTrans == '7' || cTrans == '8' || cTrans == '9')
                    && (m_iNumberStatus == NUMBER_PORZERODEC || m_iNumberStatus == NUMBER_PORDEC)) {
                // Un numero decimal
                m_jPor.setText(m_jPor.getText() + cTrans);
                m_iNumberStatus = NUMBER_PORDEC;
                m_iNumberStatusPor = NUMBERVALID;

            } else if (cTrans == '\u00a7'
                    && m_iNumberStatusInput == NUMBERVALID
                    && m_iNumberStatusPor == NUMBERZERO) {
                // Scale button pressed and a number typed as a price
                if (m_App.getDeviceScale().existsScale()
                        && security.hasPermissionByName("sales.EditLines")) {
                    try {
                        Double value = m_App.getDeviceScale().readWeight();
                        if (value != null) {
                            Product product = getInputProduct();
                            addTicketLine(product, value.doubleValue(),
                                    product.getPriceSell());
                        }
                    } catch (ScaleException e) {
                        Toolkit.getDefaultToolkit().beep();
                        new MessageInf(MessageInf.SGN_WARNING,
                                AppLocal.getIntString("message.noweight"), e)
                                .show(this);
                        stateToZero();
                    }
                } else {
                    // No existe la balanza;
                    Toolkit.getDefaultToolkit().beep();
                }
            } else if (cTrans == '\u00a7' && m_iNumberStatusInput == NUMBERZERO
                    && m_iNumberStatusPor == NUMBERZERO) {
                // Scale button pressed and no number typed.
                int i = m_ticketlines.getSelectedIndex();
                if (i < 0) {
                    Toolkit.getDefaultToolkit().beep();
                } else if (m_App.getDeviceScale().existsScale()) {
                    try {
                        Double value = m_App.getDeviceScale().readWeight();
                        if (value != null) {
                            TicketLine newline = m_oTicket.getLine(i).copyTicketLine();
                            newline.setMultiply(value.doubleValue());

                            TicketLineHelper.setPrice(newline, Math
                                    .abs(TicketLineHelper.getPrice(newline)));
                            paintTicketLine(i, newline);
                        }
                    } catch (ScaleException e) {
                        // Error de pesada.
                        Toolkit.getDefaultToolkit().beep();
                        new MessageInf(MessageInf.SGN_WARNING,
                                AppLocal.getIntString("message.noweight"), e)
                                .show(this);
                        stateToZero();
                    }
                } else {
                    // No existe la balanza;
                    Toolkit.getDefaultToolkit().beep();
                }

                // Add one product more to the selected line
            } else if (cTrans == '+' && m_iNumberStatusInput == NUMBERZERO
                    && m_iNumberStatusPor == NUMBERZERO) {

                int i = m_ticketlines.getSelectedIndex();
                if (i < 0) {
                    Toolkit.getDefaultToolkit().beep();
                } else {
                    TicketLine newline = m_oTicket.getLine(i).copyTicketLine();
                    // If it's a refund + button means one unit less
                    if (m_oTicket.getTicketType() == Ticket.RECEIPT_REFUND) {
                        newline.setMultiply(newline.getMultiply() - 1.0);
                        paintTicketLine(i, newline);
                    } else {
                        // add one unit to the selected line
                        newline.setMultiply(newline.getMultiply() + 1.0);
                        try {
                            TicketUtil.checkTicketLineProductPrefPrice(dlSales, m_oTicket, newline, m_App.getDefineLocation());
                        } catch (BasicException e) {
                            new MessageInf(MessageInf.SGN_WARNING,
                                    AppLocal.getIntString("message.checkPrefPriceError"), e)
                                    .show(this);
                        }
                        paintTicketLine(i, newline);
                    }
                }

                // Delete one product of the selected line
            } else if (cTrans == '-' && m_iNumberStatusInput == NUMBERZERO
                    && m_iNumberStatusPor == NUMBERZERO) {
                if (m_ticketlines.getRowCount() == 0) {
                    m_ticketsbag.showPrevTicket();
                    return;
                } else if (security.hasPermissionByName("sales.EditLines")) {

                    int i = m_ticketlines.getSelectedIndex();
                    if (i < 0) {
                        Toolkit.getDefaultToolkit().beep();
                    } else {
                        TicketLine newline = m_oTicket.getLine(i)
                                .copyTicketLine();
                        // If it's a refund - button means one unit more
                        if (m_oTicket.getTicketType() == Ticket.RECEIPT_REFUND) {
                            newline.setMultiply(newline.getMultiply() + 1.0);
                            if (newline.getMultiply() >= 0) {
                                removeTicketLine(i);
                            } else {
                                paintTicketLine(i, newline);
                            }
                        } else {
                            // substract one unit to the selected line
                            newline.setMultiply(newline.getMultiply() - 1.0);
                            if (newline.getMultiply() <= 0.0) {
                                removeTicketLine(i); // elimino la linea
                            } else {
                                try {
                                    TicketUtil.checkTicketLineProductPrefPrice(
                                            dlSales, m_oTicket, newline,
                                            m_App.getDefineLocation());
                                } catch (BasicException e) {
                                    new MessageInf(
                                            MessageInf.SGN_WARNING,
                                            AppLocal.getIntString("message.checkPrefPriceError"),
                                            e).show(this);
                                }
                                paintTicketLine(i, newline);
                            }
                        }
                    }
                }
                // Set n products to the selected line
            } else if (cTrans == '+' && m_iNumberStatusInput == NUMBERZERO
                    && m_iNumberStatusPor == NUMBERVALID) {
                int i = m_ticketlines.getSelectedIndex();
                if (i < 0) {
                    Toolkit.getDefaultToolkit().beep();
                } else {
                    double dPor = getPorValue();
                    TicketLine newline = m_oTicket.getLine(i).copyTicketLine();
                    if (m_oTicket.getTicketType() == Ticket.RECEIPT_REFUND) {
                        newline.setMultiply(-dPor);

                        TicketLineHelper.setPrice(newline,
                                Math.abs(TicketLineHelper.getPrice(newline)));
                        paintTicketLine(i, newline);
                    } else {
                        newline.setMultiply(dPor);

                        TicketLineHelper.setPrice(newline,
                                Math.abs(TicketLineHelper.getPrice(newline)));
                        try {
                            TicketUtil.checkTicketLineProductPrefPrice(dlSales, m_oTicket, newline, m_App.getDefineLocation());
                        } catch (BasicException e) {
                            new MessageInf(MessageInf.SGN_WARNING,
                                    AppLocal.getIntString("message.checkPrefPriceError"), e)
                                    .show(this);
                        }
                        paintTicketLine(i, newline);
                    }
                }

                // Set n negative products to the selected line
            } else if (cTrans == '-'
                    && m_iNumberStatusInput == NUMBERZERO
                    && m_iNumberStatusPor == NUMBERVALID
                    && security.hasPermissionByName("sales.EditLines")) {

                int i = m_ticketlines.getSelectedIndex();
                if (i < 0) {
                    Toolkit.getDefaultToolkit().beep();
                } else {
                    double dPor = getPorValue();
                    TicketLine newline = m_oTicket.getLine(i).copyTicketLine();
                    if (m_oTicket.getTicketType() == Ticket.RECEIPT_NORMAL) {
                        newline.setMultiply(dPor);

                        TicketLineHelper.setPrice(newline,
                                -Math.abs(TicketLineHelper.getPrice(newline)));
                        try {
                            TicketUtil.checkTicketLineProductPrefPrice(dlSales, m_oTicket, newline, m_App.getDefineLocation());
                        } catch (BasicException e) {
                            new MessageInf(MessageInf.SGN_WARNING,
                                    AppLocal.getIntString("message.checkPrefPriceError"), e)
                                    .show(this);
                        }
                        paintTicketLine(i, newline);
                    }
                }

                // Anadimos 1 producto
            } else if (cTrans == '+'
                    && m_iNumberStatusInput == NUMBERVALID
                    && m_iNumberStatusPor == NUMBERZERO
                    && security.hasPermissionByName("sales.EditLines")) {
                Product product = getInputProduct();
                addTicketLine(product, 1.0, product.getPriceSell());

                // Anadimos 1 producto con precio negativo
            } else if (cTrans == '-'
                    && m_iNumberStatusInput == NUMBERVALID
                    && m_iNumberStatusPor == NUMBERZERO
                    && security.hasPermissionByName("sales.EditLines")) {
                Product product = getInputProduct();
                addTicketLine(product, 1.0, -product.getPriceSell());

                // Anadimos n productos
            } else if (cTrans == '+'
                    && m_iNumberStatusInput == NUMBERVALID
                    && m_iNumberStatusPor == NUMBERVALID
                    && security.hasPermissionByName("sales.EditLines")) {
                Product product = getInputProduct();
                addTicketLine(product, getPorValue(), product.getPriceSell());

                // Anadimos n productos con precio negativo ?
            } else if (cTrans == '-'
                    && m_iNumberStatusInput == NUMBERVALID
                    && m_iNumberStatusPor == NUMBERVALID
                    && security.hasPermissionByName("sales.EditLines")) {
                Product product = getInputProduct();
                addTicketLine(product, getPorValue(), -product.getPriceSell());

                // Totals() Igual;
            } else if (cTrans == ' ' || cTrans == '=') {
                if (m_oTicket.getLinesCount() > 0) {

                    if (closeTicket(m_oTicket, m_oTicketExt)) {
                        // Ends edition of current receipt
                        m_ticketsbag.flushTicket();
                    } else {
                        // repaint current ticket
                        refreshTicket();
                    }
                } else {
                    Toolkit.getDefaultToolkit().beep();
                }
            }
        }
    }

    private void quickSaleByKeyStoke(char cTrans) {
        Product findProduct = null;
        try {
            findProduct = dlSales.findProductByKeyStoke(String.valueOf(cTrans));
        } catch (BasicException e) {
            Toolkit.getDefaultToolkit().beep();
            stateToZero();
            new MessageInf(MessageInf.SGN_WARNING, AppLocal.getIntString("message.noproduct")).show(this);
        }
        if (findProduct != null)
            incProduct(findProduct);
    }


    private boolean closeTicket(Ticket ticket, Object ticketext) {
        boolean resultok = false;
        cashChanged = "0.0";
        cashPaid = null;
        double cashPayed = 0.0;
        ticket.setHostName(m_App.getProperties().getHost());
        if (security.hasPermissionByName("sales.Total")) {

            try {
                // reset the payment info
                taxeslogic.calculateTaxes(ticket);
                if (TicketHelper.getTotal(ticket) >= 0.0) {
                    ticket.resetPayments(); // Only reset if is sale
                }

                ticket.setTotalTax(TicketHelper.getTax(ticket));
                ticket.setTotalPrice(TicketHelper.getTotal(ticket));
                ticket.setTotalConsultCost(TicketHelper.getTotalConsultCost(ticket));
                ticket.setTotalScore(TicketHelper.getTotalScore(ticket));

                if (executeEvent(ticket, ticketext, "ticket.total") == null) {

                    // Muestro el total
                    printTicket("Printer.TicketTotal", ticket, ticketext);

                    // Select the Payments information
                    JPaymentSelect paymentdialog = ticket
                            .getTicketType() == Ticket.RECEIPT_NORMAL ? paymentdialogreceipt
                            : paymentdialogrefund;
                    // paymentdialog.setPrintSelected("true".equals(m_jbtnconfig.getProperty("printselected",
                    // "true")));

                    paymentdialog.setTransactionID(TicketHelper
                            .getTransactionID(ticket));

                    if (paymentdialog.showDialog(ticket.getTotalPrice(),
                            ticket.getCustomer())) {

                        // assign the payments selected and calculate taxes.
                        ticket.setPayments(paymentdialog.getSelectedPayments());

                        // Asigno los valores definitivos del ticket...
                        ticket.setUser(m_App.getUserInfo()); // El usuario que lo cobra
                        ticket.setActiveCash(m_App.getUserCashIndex());
                        ticket.setDate(new Date()); // Le pongo la fecha de
                        // cobro

                        if (executeEvent(ticket, ticketext, "ticket.save") == null) {
                            // Save the receipt and assign a receipt number
                            try {
                                dlSales.saveTicket(ticket,
                                        m_App.getInventoryLocation());
                            } catch (BasicException eData) {
                                MessageInf msg = new MessageInf(
                                        MessageInf.SGN_NOTICE,
                                        AppLocal.getIntString("message.nosaveticket"),
                                        eData);
                                msg.show(this);
                                return false;
                            }

                            executeEvent(
                                    ticket,
                                    ticketext,
                                    "ticket.close",
                                    new ScriptArg("print", paymentdialog
                                            .isPrintSelected()));

                            // Print receipt.
                            if (paymentdialog.isPrintSelected())
                                printTicket("Printer.Ticket2", ticket,
                                        ticketext);
                            resultok = true;
                        }

                        for (PaymentInfo p : ticket.getPayments()) {
                            if (p.getName().equalsIgnoreCase("cash")) {
                                PaymentInfoCash pInfoCash = (PaymentInfoCash) p;
                                cashPaid = PaymentInfoHelper.printPaid((PaymentInfoCash) p);
                                if ((pInfoCash.getPaid() - pInfoCash.getTotal()) != 0.0) {
                                    cashChanged = PaymentInfoHelper
                                            .printChange((PaymentInfoCash) p);
                                    break;
                                }
                            }
                        }

                    }
                }
            } catch (TaxesException e) {
                MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                        AppLocal.getIntString("message.cannotcalculatetaxes"));
                msg.show(this);
                resultok = false;
            }
            if (!resultok) {
                // reset the payment info
                m_oTicket.resetTaxes();
                m_oTicket.resetPayments();
            }
        }

        // cancelled the ticket.total script
        // or canceled the payment dialog
        // or canceled the ticket.close script
        return resultok;
    }

    public void printTicket(String sresourcename, Ticket ticket, Object ticketext) {

        String sresource = dlSystem.getResourceAsXML(sresourcename);
        if (sresource == null) {
            MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                    AppLocal.getIntString("message.cannotprintticket"));
            msg.show(AbstractJPanelTicket.this);
        } else {
            try {
                ScriptEngine script = ScriptFactory
                        .getScriptEngine(ScriptFactory.VELOCITY);
                script.put("taxes", taxcollection);
                script.put("taxeslogic", taxeslogic);
                script.put("ticket", new TicketWarp(ticket));
                script.put("place", ticketext);
                script.put("warehouse", m_App.getsWareHouse());
                m_TTP.printTicket(script.eval(sresource).toString());
            } catch (ScriptException e) {
                MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                        AppLocal.getIntString("message.cannotprintticket"), e);
                msg.show(AbstractJPanelTicket.this);
            } catch (TicketPrinterException e) {
                MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                        AppLocal.getIntString("message.cannotprintticket"), e);
                msg.show(AbstractJPanelTicket.this);
            }
        }
    }

    protected void printReport(String resourcefile, Ticket ticket, Object ticketext) {

        try {

            JasperReport jr;

            InputStream in = getClass().getResourceAsStream(
                    resourcefile + ".ser");
            if (in == null) {
                // read and compile the report
                JasperDesign jd = JRXmlLoader.load(getClass()
                        .getResourceAsStream(resourcefile + ".jrxml"));
                jr = JasperCompileManager.compileReport(jd);
            } else {
                // read the compiled reporte
                ObjectInputStream oin = new ObjectInputStream(in);
                jr = (JasperReport) oin.readObject();
                oin.close();
            }

            // Construyo el mapa de los parametros.
            Map reportparams = new HashMap();
            // reportparams.put("ARG", params);
            try {
                reportparams.put("REPORT_RESOURCE_BUNDLE",
                        ResourceBundle.getBundle(resourcefile + ".properties"));
            } catch (MissingResourceException e) {
            }
            reportparams.put("TAXESLOGIC", taxeslogic);

            Map reportfields = new HashMap();
            reportfields.put("TICKET", new TicketWarp(ticket));
            reportfields.put("PLACE", ticketext);
            reportfields.put("WAREHOUSE", m_App.getsWareHouse());

            JasperPrint jp = JasperFillManager.fillReport(jr, reportparams,
                    new JRMapArrayDataSource(new Object[]{reportfields}));

            PrintService service = ReportUtils.getPrintService(m_App
                    .getProperties().getProperty("machine.printername"));

            JRPrinterAWT300
                    .printPages(jp, 0, jp.getPages().size() - 1, service);

        } catch (Exception e) {
            MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                    AppLocal.getIntString("message.cannotloadreport"), e);
            msg.show(this);
        }
    }

    private void visorTicketLine(TicketLine oLine) {
        if (oLine == null) {
            m_App.getDeviceTicket().getDeviceDisplay().clearVisor();
        } else {
            try {
                ScriptEngine script = ScriptFactory
                        .getScriptEngine(ScriptFactory.VELOCITY);
                script.put("ticketline", new TicketLineWarp(oLine));
                m_TTP.printTicket(script.eval(
                        dlSystem.getResourceAsXML("Printer.TicketLine"))
                        .toString());
            } catch (ScriptException e) {
                MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                        AppLocal.getIntString("message.cannotprintline"), e);
                msg.show(AbstractJPanelTicket.this);
            } catch (TicketPrinterException e) {
                MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                        AppLocal.getIntString("message.cannotprintline"), e);
                msg.show(AbstractJPanelTicket.this);
            }
        }
    }

    private Object evalScript(ScriptObject scr, String resource, ScriptArg... args) {

        // resource here is guaratied to be not null
        try {
            scr.setSelectedIndex(m_ticketlines.getSelectedIndex());
            return scr.evalScript(dlSystem.getResourceAsXML(resource), args);
        } catch (ScriptException e) {
            MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                    AppLocal.getIntString("message.cannotexecute"), e);
            msg.show(this);
            return msg;
        }
    }

    public void evalScriptAndRefresh(String resource, ScriptArg... args) {

        if (resource == null) {
            MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                    AppLocal.getIntString("message.cannotexecute"));
            msg.show(this);
        } else {
            ScriptObject scr = new ScriptObject(m_oTicket, m_oTicketExt);
            scr.setSelectedIndex(m_ticketlines.getSelectedIndex());
            evalScript(scr, resource, args);
            refreshTicket();
            setSelectedIndex(scr.getSelectedIndex());
        }
    }

    public void print(String resource) {
        printTicket(resource, m_oTicket, m_oTicketExt);
    }

    private Object executeEventAndRefresh(String eventkey, ScriptArg... args) {

        String resource = m_jbtnconfig.getEvent(eventkey);
        if (resource == null) {
            return null;
        } else {
            ScriptObject scr = new ScriptObject(m_oTicket, m_oTicketExt);
            scr.setSelectedIndex(m_ticketlines.getSelectedIndex());
            Object result = evalScript(scr, resource, args);
            refreshTicket();
            setSelectedIndex(scr.getSelectedIndex());
            return result;
        }
    }

    private Object executeEvent(Ticket ticket, Object ticketext, String eventkey,
                                ScriptArg... args) {

        String resource = m_jbtnconfig.getEvent(eventkey);
        if (resource == null) {
            return null;
        } else {
            ScriptObject scr = new ScriptObject(ticket, ticketext);
            return evalScript(scr, resource, args);
        }
    }

    public String getResourceAsXML(String sresourcename) {
        return dlSystem.getResourceAsXML(sresourcename);
    }

    public BufferedImage getResourceAsImage(String sresourcename) {
        return DataLogicSystemHelper.getResourceAsImage(dlSystem, sresourcename);
    }

    private void setSelectedIndex(int i) {
        if (i >= 0 && i < m_oTicket.getLinesCount()) {
            m_ticketlines.setSelectedIndex(i);
        } else if (m_oTicket.getLinesCount() > 0) {
            m_ticketlines.setSelectedIndex(m_oTicket.getLinesCount() - 1);
        }
    }

    protected javax.swing.JButton jEditAttributes;
    private JProductFinder productFinder;

    protected void m_jbtnScaleActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_m_jbtnScaleActionPerformed
        stateTransition('\u00a7');

    }// GEN-LAST:event_m_jbtnScaleActionPerformed

    protected void m_jEditLineActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_m_jEditLineActionPerformed
        if (!isEditAble)
            return;
        int i = m_ticketlines.getSelectedIndex();
        if (i < 0) {
            Toolkit.getDefaultToolkit().beep(); // no line selected
        } else {
            try {
                TicketLine selectedline = m_oTicket.getLine(i);
                if (selectedline != null && selectedline.isServiceTicketLine()) {
                    JServingsEditorDialog servingsEditorDialog = JServingsEditorDialog
                            .getDialog(this);
                    servingsEditorDialog.init(dlSales,
                            selectedline.getServings(), true);
                    servingsEditorDialog.setVisible(true);
                    if (servingsEditorDialog.isOK()) {
                        selectedline.setServings(servingsEditorDialog
                                .getServings());
                        paintTicketLine(i, selectedline);
                    }
                } else {
                    TicketLine oldline = m_oTicket.getLine(i);
                    double oldMultipy = oldline.getMultiply();
                    TicketLine newline = JProductLineEdit.showMessage(
                            this, m_App, oldline, dlSales, dlSystem, security);
                    if (newline != null && newline.getProductID() != null) {
                        if (newline.getMultiply() != oldMultipy) {
                            if (m_oTicket.getTicketType() == Ticket.RECEIPT_NORMAL && isCheckProductLocation && !dlSales.isProductStoreEnough(m_App.getInventoryLocation(), newline.getProductID(), newline.getMultiply())) {
                                new MessageInf(MessageInf.SGN_WARNING, AppLocal.getIntString("message.productNoStoreEnough")).show(this);
                                return;
                            }
                            TicketUtil.checkTicketLineProductPrefPrice(dlSales, m_oTicket, newline, m_App.getDefineLocation());
                        }
                        // line has been modified
                        paintTicketLine(i, newline);
                    }
                }
            } catch (BasicException e) {
                new MessageInf(e).show(this);
            }
        }

    }// GEN-LAST:event_m_jEditLineActionPerformed

    protected void m_jEnterActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_m_jEnterActionPerformed
        stateTransition('\n');

    }// GEN-LAST:event_m_jEnterActionPerformed

    protected void m_jNumberKeysKeyPerformed(com.openbravo.beans.JNumberEvent evt) {// GEN-FIRST:event_m_jNumberKeysKeyPerformed
        stateTransition(evt.getKey());

    }// GEN-LAST:event_m_jNumberKeysKeyPerformed

    protected void m_jKeyFactoryKeyTyped(java.awt.event.KeyEvent evt) {// GEN-FIRST:event_m_jKeyFactoryKeyTyped
        m_jKeyFactory.setText(null);
        stateTransition(evt.getKeyChar());

    }// GEN-LAST:event_m_jKeyFactoryKeyTyped

    protected void m_jDeleteActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_m_jDeleteActionPerformed
        if (!isEditAble)
            return;
        int i = m_ticketlines.getSelectedIndex();
        if (i < 0) {
            Toolkit.getDefaultToolkit().beep(); // No hay ninguna seleccionada
        } else {
            removeTicketLine(i); // elimino la linea
        }

    }// GEN-LAST:event_m_jDeleteActionPerformed

    protected void m_jUpActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_m_jUpActionPerformed

        m_ticketlines.selectionUp();

    }// GEN-LAST:event_m_jUpActionPerformed

    protected void m_jDownActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_m_jDownActionPerformed

        m_ticketlines.selectionDown();

    }// GEN-LAST:event_m_jDownActionPerformed

    protected void m_jListActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_m_jListActionPerformed
        if (!isEditAble)
            return;
        Product prod = JProductFinder.showMessage(
                AbstractJPanelTicket.this, dlSales);
        if (prod != null) {
            buttonTransition(prod);
        }

    }// GEN-LAST:event_m_jListActionPerformed

    protected void btnCustomerActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_btnCustomerActionPerformed
        if (!isEditAble)
            return;
        JCustomerFinder finder = JCustomerFinder.getCustomerFinder(this,
                this.dlSales);
        finder.search(m_oTicket.getCustomer());
        finder.setVisible(true);

        try {
            CustomerInfo custInfo = finder.getSelectedCustomer();
            BusinessPartner customer = null;
            if (custInfo != null) {
                customer = (BusinessPartner) dlSales.findByStringId(BusinessPartner.class, finder
                        .getSelectedCustomer().getId());
            }
            TicketUtil.changeCustomer(dlSales, m_oTicket, customer, priceGroup);
            m_oTicket.setCustomer(customer);
        } catch (BasicException e) {
            MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                    AppLocal.getIntString("message.cannotfindcustomer"), e);
            msg.show(this);
        }
        refreshTicket();

    }// GEN-LAST:event_btnCustomerActionPerformed

    protected void addNewCustomer() {
        if (!isEditAble)
            return;
        if (!RoleSwingUtil.hasPermission(AbstractJPanelTicket.this, (AppUser) m_App
                        .getAppUserView().getUser(), dlSystem,
                RoleUtil.Permission_ADD_CUSTOMER))
            return;

        if (customerCreateDialog == null)
            customerCreateDialog = JEditorWarpDialog.getInstance(this).init(dlSales,
                    new CustomersEditor(dlSales, new DirtyManager()));

        try {
            customerCreateDialog.activate();
        } catch (BasicException e) {
            JMessageDialog.showMessage(
                    this,
                    new MessageInf(MessageInf.SGN_WARNING, AppLocal
                            .getIntString("message.notactive"), e));
            return;
        }
        customerCreateDialog.writeValueInsert(null);
        if (customerCreateDialog.getRetObj() != null) {
            try {
                TicketUtil.changeCustomer(dlSales, m_oTicket,
                        (BusinessPartner) customerCreateDialog.getRetObj(), priceGroup);
                m_oTicket.setCustomer((BusinessPartner) customerCreateDialog.getRetObj());
            } catch (BasicException e) {
                new MessageInf(e).show(this);
            }
            refreshTicket();
        }
    }

    protected void btnSplitActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_btnSplitActionPerformed
        if (!isEditAble)
            return;
        if (m_oTicket.getLinesCount() > 0) {
            ReceiptSplit splitdialog = ReceiptSplit.getDialog(
                    this, dlSystem.getResourceAsXML("Ticket.Line"), dlSales,
                    dlCustomers, taxeslogic);
            Ticket ticket1 = m_oTicket.copyTicket();
            Ticket ticket2 = new Ticket();
            ticket2.setCustomer(m_oTicket.getCustomer());

            if (splitdialog.showDialog(ticket1, ticket2, m_oTicketExt)) {
                if (closeTicket(ticket2, m_oTicketExt)) { // already checked
                    // that number of
                    // lines > 0
                    if (printManager != null) {
                        try {
                            printManager.fireTicketCreated(new TicketEvent(
                                    ticket2));
                            printManager.fireTicketFlushed(new TicketEvent(
                                    ticket2));
                        } catch (TicketPrinterException e) {
                            e.printStackTrace();
                        } catch (ScriptException e) {
                            e.printStackTrace();
                        }
                    }
                    setActiveTicket(ticket1, m_oTicketExt, true);// set result ticket
                    if (printManager != null) {
                        try {
                            printManager.fireTicketCreated(new TicketEvent(ticket1));
                        } catch (TicketPrinterException e) {
                            e.printStackTrace();
                        } catch (ScriptException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }

    }// GEN-LAST:event_btnSplitActionPerformed

    protected void jEditAttributesActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_jEditAttributesActionPerformed
        if (!isEditAble)
            return;
        int i = m_ticketlines.getSelectedIndex();
        if (i < 0) {
            Toolkit.getDefaultToolkit().beep(); // no line selected
        } else {
            try {
                TicketLine line = m_oTicket.getLine(i);
                JProductAttEdit attedit = JProductAttEdit
                        .getAttributesEditor(this, this.dlSales);
                attedit.editAttributes(line.getProductAttSetId(),
                        line.getProductAttSetInstId(), line.getProductid());
                attedit.setVisible(true);
                if (attedit.isOK()) {
                    // The user pressed OK
                    line.setProductAttSetInstId(attedit.getAttributeSetInstance().getId());
                    line.setProductAttSetInstDesc(attedit.getAttributeSetInstance().getDescription());
                    line.setAttrPrice(attedit.getAttributeSetInstance().getDiffPrice());
                    line.setAttrPriceCost(attedit.getAttributeSetInstance().getDiffPriceCost());
                    paintTicketLine(i, line);
                }
            } catch (BasicException ex) {
                MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                        AppLocal.getIntString("message.cannotfindattributes"),
                        ex);
                msg.show(this);
            }
        }

    }// GEN-LAST:event_jEditAttributesActionPerformed

    protected void m_jEditLineAttrib() {
        if (!isEditAble)
            return;
        int i = m_ticketlines.getSelectedIndex();
        if (i < 0) {
            Toolkit.getDefaultToolkit().beep(); // no line selected
        } else {
            try {
                TicketLine line = m_oTicket.getLine(i);
                JTicketLinePropEdit propEdit = JTicketLinePropEdit.getPropEdit(
                        this,
                        line.getProperty(TicketLine.TICKETlINE_EXTPROP, ""));
                propEdit.setVisible(true);
                if (propEdit.isOK()) {
                    line.setProperty(TicketLine.TICKETlINE_EXTPROP,
                            propEdit.getRetProps());
                    paintTicketLine(i, line);
                }
            } catch (BasicException ex) {
                MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                        AppLocal.getIntString("message.cannotfindattributes"),
                        ex);
                msg.show(this);
            }
        }
    }

    public void changeTicketRate() {
        if (!isEditAble)
            return;
        if (!RoleSwingUtil.hasPermission(AbstractJPanelTicket.this, (AppUser) m_App
                        .getAppUserView().getUser(), dlSystem,
                RoleUtil.Permission_CHANGE_TICKET_RATE))
            return;
        JChangeRateDialog rantDialog = JChangeRateDialog.getDialog(this,
                m_oTicket.getM_dPriceRate());
        rantDialog.setVisible(true);
        if (rantDialog.isOk()) {
            Double changedRant = rantDialog.getChangeRate();
            TicketUtil.changeRate(m_oTicket, changedRant);
        }
        refreshTicket();
    }

    protected void changeTicketType() {
        if (!isEditAble)
            return;
        if (m_oTicket.getLinesCount() > 0) {
            MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
                    AppLocal.getIntString("message.theTickeMustEmpty"));
            msg.show(this);
            return;
        }

        if (!RoleSwingUtil.hasPermission(AbstractJPanelTicket.this, (AppUser) m_App
                        .getAppUserView().getUser(), dlSystem,
                RoleUtil.Permission_CHANGE_TICKET_TYPE))
            return;

        if (Ticket.RECEIPT_NORMAL == m_oTicket.getTicketType()) {
            m_oTicket.setTicketType(Ticket.RECEIPT_REFUND);
        } else if (Ticket.RECEIPT_REFUND == m_oTicket.getTicketType()) {
            m_oTicket.setTicketType(Ticket.RECEIPT_NORMAL);
        }
        printPartialTotals();
    }


    protected void addServings() {
        if (!isEditAble)
            return;
        try {
            JServingsEditorDialog servingsEditorDialog = JServingsEditorDialog
                    .getDialog(this);
            servingsEditorDialog.init(dlSales, null, true);
            servingsEditorDialog.setVisible(true);
            if (servingsEditorDialog.isOK()) {
                Serving retServings = servingsEditorDialog.getServings();
                if (retServings != null) {
                    String tcid = ((TaxCategory) taxcategoriesmodel
                            .getSelectedItem()).getID();
                    Tax tax = taxeslogic.getTaxInfo(tcid,
                            m_oTicket.getCustomer());
                    addTicketLine(new TicketLine(retServings, tax,
                            m_oTicket.getM_dPriceRate()));
                }
            }
        } catch (BasicException ex) {
            JMessageDialog.showMessage(
                    this,
                    new MessageInf(MessageInf.SGN_WARNING, AppLocal
                            .getIntString("message.notactive"), ex));
            return;
        }
    }

    JPhysicalBondDialog jPhysicalBondDialog;

    protected void physicalBondTicket() {
        if (jPhysicalBondDialog == null)
            jPhysicalBondDialog = JPhysicalBondDialog.getDialog(this, dlSales, m_App.getInventoryLocation());
        jPhysicalBondDialog.setVisible(true);
    }


    protected void showProductDetail() {
        JProductDetail.getInstance(this, dlSales, dlSystem, m_App).setVisible(true);
    }

    public class ScriptObject {
        private Ticket ticket;
        private Object ticketext;
        private int selectedindex;

        private ScriptObject(Ticket ticket, Object ticketext) {
            this.ticket = ticket;
            this.ticketext = ticketext;
        }

        public double getInputValue() {
            if (m_iNumberStatusInput == NUMBERVALID
                    && m_iNumberStatusPor == NUMBERZERO) {
                return AbstractJPanelTicket.this.getInputValue();
            } else {
                return 0.0;
            }
        }

        public int getSelectedIndex() {
            return selectedindex;
        }

        public void setSelectedIndex(int i) {
            selectedindex = i;
        }

        public void printReport(String resourcefile) {
            AbstractJPanelTicket.this.printReport(resourcefile, ticket,
                    ticketext);
        }

        public void printTicket(String sresourcename) {
            AbstractJPanelTicket.this.printTicket(sresourcename, ticket,
                    ticketext);
        }

        public Object evalScript(String code, ScriptArg... args)
                throws ScriptException {

            ScriptEngine script = ScriptFactory
                    .getScriptEngine(ScriptFactory.BEANSHELL);
            script.put("ticket", ticket);
            script.put("place", ticketext);
            script.put("taxes", taxcollection);
            script.put("taxeslogic", taxeslogic);
            script.put("user", m_App.getAppUserView().getUser());
            script.put("sales", this);

            // more arguments
            for (ScriptArg arg : args) {
                script.put(arg.getKey(), arg.getValue());
            }

            return script.eval(code);
        }
    }


    public JProductFinder getProductFinder() {
        if (productFinder == null)
            productFinder = JProductFinder.getInstance(this, dlSales, JProductFinder.PRODUCT_ALL);
        return productFinder;
    }

    public boolean isEditAble() {
        return isEditAble;
    }

    protected javax.swing.JTextField m_jKeyFactory;
    protected javax.swing.JLabel m_jTicketId;
    protected javax.swing.JLabel m_jPor;
    protected javax.swing.JLabel m_jPrice;
    protected javax.swing.JToggleButton m_jaddtax;

    @Override
    public String getModelName() {
        return POS_UI_Swing_Model.MODEL_NAME;
    }

    protected POS_UI_Swing_Model mode;

    @Override
    public void setModel(POS_UI_Swing_Model mode) {
        dlSystem = mode.getDLSystem();
        dlSales = mode.getDLSales();
        dlCustomers = mode.getDLCustomer();
        dlReceipts = mode.getDLReceipts();
        this.mode = mode;
        security = mode.getModelSecurityManager();
    }


    public I_DataLogicSystem getDlSystem() {
        return dlSystem;
    }

    public I_DataLogicSales getDlSales() {
        return dlSales;
    }

    public I_DataLogicCustomers getDlCustomers() {
        return dlCustomers;
    }

    public I_DataLogicReceipts getDlReceipts() {
        return dlReceipts;
    }


    @Override
    public I_SecurityManager getSecurityManager() {
        return security;
    }


}